#pragma once
#include "Util.hpp"
#include <mutex>
#include <mysql/mysql.h>

namespace aod
{
    const std::string host = "127.0.0.1";
    const std::string user = "magician";
    const std::string password = "8456852";
    const std::string db = "aod_system";
    int port = 3306;
    static MYSQL *MysqlInit()
    {
        MYSQL* mysql = mysql_init(nullptr);
        if(!mysql_real_connect(mysql, host.c_str(), user.c_str(),password.c_str(), db.c_str(), port, nullptr, 0))
        {
            std::cout << "连接数据库失败" << std::endl;
            mysql_close(mysql);
            return nullptr;
        }
        mysql_set_character_set(mysql, "utf8");
        return mysql;
    }
    static void MysqlDestory(MYSQL* mysql)
    {
        if(mysql != nullptr)
        {
            mysql_close(mysql);
        }
    }
    static bool MysqlQuery(MYSQL* mysql, const std::string &sql)
    {
        int ret = mysql_query(mysql, sql.c_str());
        if(ret != 0)
        {
            std::cout << sql << " failed " << std::endl;
            std::cout << mysql_error(mysql) << std::endl;
            return false;
        }
        return true;
    }
    class TableVideo
    {
    private:
        MYSQL* _mysql;
        std::mutex _mutex;
    public:
        TableVideo()
        {
            _mysql = MysqlInit();
            if(_mysql == nullptr)
                exit(-1);
        }
        ~TableVideo()
        {
            MysqlDestory(_mysql);
        }
        bool Insert(const Json::Value & val)
        {
            // id name info video image
            std::string sql = "insert into tb_video values (null, '" + val["name"].asString() +"','"+ val["info"].asString() +"','"+ \
                                val["video"].asString() +"','" + val["image"].asCString() + "');";
            // sprintf(&sql[0], "insert into tb_video values (null, '%s','%s','%s','%s');",
            //         val["name"].asCString(), val["info"].asCString(), val["video"].asCString(), val["image"].asCString());
            return MysqlQuery(_mysql, sql);
        }
        bool Delete(const int video_id)
        {
            std::string sql = "delete from tb_video where id = " + std::to_string(video_id) + ";";
            // sprintf(&sql[0], "delete from tb_video where id = %d;", video_id);
            return MysqlQuery(_mysql, sql);
        }
        bool Update(const int video_id, const Json::Value & val)
        {
            std::string sql = "update tb_video set name = '"+ val["name"].asString() +"', info = '"+ \
                                val["info"].asString() +"' where id = "+ std::to_string(video_id) + ";";
            return MysqlQuery(_mysql, sql);
        }
        bool Select(const std::string & sql, Json::Value *out, bool flag = true)
        {
            MYSQL_RES* res = nullptr;
            {
                std::lock_guard<std::mutex> lock(_mutex);
                if(!MysqlQuery(_mysql, sql))
                    return false;
                res = mysql_store_result(_mysql);
                if(res == nullptr)
                {
                    std::cout << "mysql store result failed" << std::endl;
                    return false;
                }
            }
            int num_row = mysql_num_rows(res);
            int num_col = mysql_num_fields(res);
            for(int i = 0; i < num_row; i++)
            {
                MYSQL_ROW rows = mysql_fetch_row(res);
                Json::Value video;
                video["id"] = rows[0];
                video["name"] = rows[1];
                video["info"] = rows[2];
                video["video"] = rows[3];
                video["image"] = rows[4];
                if(flag) out->append(video);
                else *out = video;
            }
            mysql_free_result(res);
            return true;
        }
        bool SelectAll(Json::Value* out)
        {
            std::string sql = "select * from tb_video;";
            bool ret = Select(sql, out);
            return ret;
        }
        bool SelectOne(const int video_id, Json::Value* out)
        {
            std::string sql = "select * from tb_video where id = " + std::to_string(video_id) + ";";
            bool ret = Select(sql, out, false);
            return ret;
        }
        bool SelectLike(const std::string & s, Json::Value* out)
        {
            std::string sql = "select * from tb_video where info like '%"+ s + "%' or name like '%" + s + "%';";
            bool ret = Select(sql, out);
            return ret;
        }
    };
}
